#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
模型19：公司管辖范围外发生业务招待费模型

主要功能：
1. 读取多个数据文件
2. 根据组织机构名称匹配所在城市
3. 根据销方单位名称中的敏感词进行分级
4. 根据销方税号匹配行政区划所在地
5. 对比并筛选地址不匹配数据
"""

import pandas as pd
from pathlib import Path

# 配置常量
DATA_DIR = Path("data")
OUTPUT_DIR = DATA_DIR / "alldata"  # 输出目录

# 输入文件
EXPENSE_FILE = DATA_DIR / "费用报销票据信息.xlsx"
CITY_FILE = DATA_DIR / "序号19-华北油田二级单位所在城市-1.xlsx"
ADMIN_CODE_FILE = DATA_DIR / "序号19-2023年中华人民共和国县以上行政区划代码.xlsx"

# 敏感词列表
SENSITIVE_KEYWORDS = ["商贸", "超市", "贸易", "烟"]

def load_data():
    """
    加载所有数据文件
    
    Returns:
        tuple: (费用数据, 城市数据, 行政区划数据, 明细数据)
    """
    # 确保输出目录存在
    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    
    try:
        # 读取所有数据文件
        expense_df = pd.read_excel(EXPENSE_FILE)
        city_df = pd.read_excel(CITY_FILE)
        # 跳过第一行，使用第二行作为列名
        admin_code_df = pd.read_excel(ADMIN_CODE_FILE, skiprows=1)
        
        # 筛选业务类型为0015的记录，并确保保持4位格式
        expense_df['业务类型'] = expense_df['业务类型'].astype(str).str.zfill(4)
        expense_df = expense_df[expense_df['业务类型'] == '0015'].copy()
        
        if expense_df.empty:
            print("警告：筛选业务类型为0015后没有符合条件的记录")
            return None, None, None
        
        return expense_df, city_df, admin_code_df
    except Exception as e:
        print(f"读取数据时出错: {str(e)}")
        raise

def match_organization_city(expense_df, city_df):
    """
    根据组织机构名称匹配所在城市
    
    Args:
        expense_df: DataFrame 费用数据
        city_df: DataFrame 城市数据
        
    Returns:
        DataFrame: 匹配后的数据
    """
    try:
        # 创建结果DataFrame
        result_df = expense_df.copy()
        
        # 将组织机构名称中的"分公司"替换为"公司"
        result_df['组织机构名称_处理'] = result_df['组织机构名称'].str.replace('分公司', '公司')
        
        # 提取关联单位名称（假设格式为"华北油田公司/XX"）
        result_df['关联单位名称'] = result_df['组织机构名称_处理'].str.split('/').str[-1]
        
        # 与城市数据进行匹配
        result_df = result_df.merge(
            city_df[['关联单位名称', '所在城市']],
            on='关联单位名称',
            how='left'
        )
        
        # 删除临时列
        result_df = result_df.drop('组织机构名称_处理', axis=1)
        
        return result_df
        
    except Exception as e:
        print(f"匹配城市数据时出错: {str(e)}")
        raise

def classify_vendor_level(df):
    """
    根据销方单位名称中的敏感词对记录进行分级
    
    Args:
        df: DataFrame 包含销方单位信息的数据
        
    Returns:
        DataFrame: 添加了分级信息的数据
    """
    try:
        result_df = df.copy()
        
        # 添加分级列
        result_df['风险等级'] = '二级'  # 默认为二级
        
        # 检查销方单位名称中是否包含敏感词
        for keyword in SENSITIVE_KEYWORDS:
            mask = result_df['销方单位'].str.contains(keyword, na=False, case=True)
            result_df.loc[mask, '风险等级'] = '一级'
        
        # 添加分级说明列
        result_df['分级说明'] = '正常'
        mask = result_df['风险等级'] == '一级'
        result_df.loc[mask, '分级说明'] = result_df.loc[mask, '销方单位'].apply(
            lambda x: f"销方单位名称含有敏感词：{'、'.join([k for k in SENSITIVE_KEYWORDS if k in str(x)])}"
        )
        
        return result_df
        
    except Exception as e:
        print(f"分级处理时出错: {str(e)}")
        raise

def match_tax_number_location(df, admin_code_df):
    """
    根据销方税号匹配行政区划所在地
    
    Args:
        df: DataFrame 包含销方税号的数据
        admin_code_df: DataFrame 行政区划代码数据
        
    Returns:
        DataFrame: 添加了税号所在地信息的数据
    """
    try:
        result_df = df.copy()
        
        # 提取税号的3-8位作为行政区划代码
        result_df['行政区划代码'] = result_df['销方税号'].str[2:8]
        
        # 确保行政区划代码列的类型与admin_code_df中的类型一致
        admin_code_df['行政区划代码'] = admin_code_df['行政区划代码'].astype(str)
        
        # 与行政区划数据进行匹配
        result_df = result_df.merge(
            admin_code_df[['行政区划代码', '城市名称']],
            on='行政区划代码',
            how='left'
        )
        
        # 重命名列
        result_df = result_df.rename(columns={'城市名称': '销方税号所在地'})
        
        # 删除临时列
        result_df = result_df.drop('行政区划代码', axis=1)
        
        return result_df
        
    except Exception as e:
        print(f"匹配税号所在地时出错: {str(e)}")
        raise

def filter_location_mismatch(df):
    """
    对比销方税号所在地与所在城市，筛选不匹配的数据
    
    Args:
        df: DataFrame 包含销方税号所在地和所在城市的数据
        
    Returns:
        tuple: (完整数据DataFrame, 不匹配数据DataFrame)
    """
    try:
        result_df = df.copy()
        
        # 添加地址匹配状态列
        result_df['地址匹配状态'] = '匹配'
        
        # 逐行检查地址匹配情况
        for idx, row in result_df.iterrows():
            tax_location = str(row['销方税号所在地']) if pd.notna(row['销方税号所在地']) else ''
            org_city = str(row['所在城市']) if pd.notna(row['所在城市']) else ''
            
            if pd.isna(row['销方税号所在地']):
                result_df.loc[idx, '地址匹配状态'] = '税号地址未知'
            elif pd.isna(row['所在城市']):
                result_df.loc[idx, '地址匹配状态'] = '组织所在地未知'
            elif org_city not in tax_location and tax_location not in org_city:
                result_df.loc[idx, '地址匹配状态'] = '不匹配'
        
        # 筛选不匹配的数据
        mismatch_df = result_df[result_df['地址匹配状态'] != '匹配'].copy()
        
        return result_df, mismatch_df
        
    except Exception as e:
        print(f"筛选地址不匹配数据时出错: {str(e)}")
        raise

def main(once = False):
    """主程序入口"""
    try:
        print("开始加载数据...")
        expense_df, city_df, admin_code_df = load_data()
        
        if any(df.empty for df in [expense_df, city_df, admin_code_df]):
            print("错误：存在空数据文件")
            return False
            
        print("正在进行组织机构与城市匹配...")
        result_df = match_organization_city(expense_df, city_df)
        
        print("正在进行销方单位分级...")
        result_df = classify_vendor_level(result_df)
        
        print("正在匹配销方税号所在地...")
        result_df = match_tax_number_location(result_df, admin_code_df)
        
        print("正在筛选地址不匹配数据...")
        result_df, mismatch_df = filter_location_mismatch(result_df)
        
        # 确保业务类型保持4位格式
        mismatch_df['业务类型'] = mismatch_df['业务类型'].astype(str).str.zfill(4)

        if once:
            return mismatch_df
        
        # 保存不匹配数据
        mismatch_file = OUTPUT_DIR / "地址不匹配数据.xlsx"
        with pd.ExcelWriter(mismatch_file, engine='openpyxl') as writer:
            mismatch_df.to_excel(writer, index=False)
            # 设置业务类型列为文本格式
            worksheet = writer.sheets['Sheet1']
            for idx, col in enumerate(mismatch_df.columns):
                if col == '业务类型':
                    for row in range(2, len(mismatch_df) + 2):  # Excel是1-based，第一行是标题
                        cell = worksheet.cell(row=row, column=idx + 1)
                        cell.number_format = '@'  # 设置单元格格式为文本
        print(f"\n地址不匹配数据已保存至: {mismatch_file}")
        print(f"不匹配记录数: {len(mismatch_df)}")
        
        # 输出分级统计
        level_stats = result_df['风险等级'].value_counts()
        print("\n分级统计:")
        for level, count in level_stats.items():
            print(f"{level}: {count}条记录")
        
        # 输出地址匹配状态统计
        match_stats = result_df['地址匹配状态'].value_counts()
        print("\n地址匹配状态统计:")
        for status, count in match_stats.items():
            print(f"{status}: {count}条记录")
        
        return True
        
    except Exception as e:
        print(f"处理过程中出现错误: {str(e)}")
        raise

if __name__ == "__main__":
    main() 